home *** CD-ROM | disk | FTP | other *** search
/ Gigarom 1 / Gigarom Macintosh Archives (Quantum Leap)(CDRM1080320)(1993).iso / FILES / DEV / I-Z / TransSkel.cpt / TransDisplay.pas < prev    next >
Pascal/Delphi Source File  |  1987-02-09  |  27KB  |  1,024 lines

  1. {    TransDisplay version 1.0 - TransSkel plug-in module supporting}
  2. {    an arbitrary number of generic display windows with memory.}
  3.  
  4. {    TransSkel and TransDisplay are public domain, and are written by:}
  5.  
  6. {            Paul DuBois}
  7. {            Wisconsin Regional Primate Research Center}
  8. {            1220 Capital Court}
  9. {            Madison WI  53706  USA}
  10.  
  11. {    UUCP:        [allegra,ihnp4,seismo]!uwvax !uwmacc !dubois }
  12. {    ARPA :     dubois @ unix.macc.wisc.edu }
  13. {                dubois @ rhesus.primate.wisc.edu }
  14.  
  15. {    The Pascal Version of TransSkel is public domain and was ported by        }
  16.  
  17. {            Owen Hartnett            }
  18. {            Ωhm Software            }
  19. {            163 Richard Drive        }
  20. {            Tiverton, RI 02878        }
  21.  
  22. {    CSNET:    omh@cs.brown.edu.CSNET                                             }
  23. {    ARPA:        omh%cs.brown.edu@relay.cs.net-relay.ARPA                        }
  24. {    UUCP:        [ihnp4,allegra]!brunix !omh                                            }
  25.  
  26. {    Psychic Wavelength:  182.2245 Meters  (sorry, couldn't resist)    }
  27.  
  28. {    This version of TransDisplay written for Lightspeed Pascal.  Lightspeed Pascal}
  29. {    is a trademark of:}
  30. {            THINK Technologies, Inc}
  31. {            420 Bedford Street  Suite 350}
  32. {            Lexington, MA  02173  USA}
  33.  
  34.  
  35.  { History}
  36. {  08/25/86    Genesis.  Beta version.}
  37. {  09/15/86    Changed to allow arbitrary number of windows.  Changed}
  38. {             version number to 1.0.}
  39. {  01/10/87    Ported to LightSpeed Pascal by Owen Hartnett                }
  40. {    Ωhm Software, 163 Richard Drive, Tiverton, RI 02878                }
  41.  
  42. UNIT TransDisplay;
  43.  
  44. INTERFACE
  45.  
  46.     USES
  47.         TransSkelPas;
  48.  
  49.     PROCEDURE SetDWindow (theWind : WindowPtr);
  50.     PROCEDURE DisplayString (theStr : str255);
  51.     PROCEDURE DisplayHexLong (l : longint);
  52.     PROCEDURE DisplayHexInt (i : integer);
  53.     PROCEDURE DisplayHexChar (c : char);
  54.     PROCEDURE DisplayBoolean (b : Boolean);
  55.     PROCEDURE DisplayChar (c : char);
  56.     PROCEDURE DisplayInt (i : integer);
  57.     PROCEDURE DisplayLong (l : longint);
  58.     PROCEDURE DisplayLn;
  59.     PROCEDURE DisplayText (theText : Ptr;
  60.                                     len : longint);
  61.     FUNCTION GetNewDWindow (resourceNum : integer;
  62.                                     behind : WindowPtr) : WindowPtr;
  63.     FUNCTION NewDWindow (bounds : Rect;
  64.                                     title : Str255;
  65.                                     visible : Boolean;
  66.                                     behind : WindowPtr;
  67.                                     goAway : Boolean;
  68.                                     refcon : longint) : WindowPTr;
  69.     PROCEDURE FlushDWindow (theWind : WindowPtr;
  70.                                     byteCount : longint);
  71.     PROCEDURE GetDWindow (VAR theWind : WindowPtr);
  72.     PROCEDURE SetDWindowFlush (theWind : WindowPtr;
  73.                                     maxText, flushAmt : longint);
  74.     PROCEDURE SetDWindowNotify (theWind : WindowPTr;
  75.                                     p : ProcPtr);
  76.     PROCEDURE setDWindowPos (theWind : WindowPtr;
  77.                                     lineNum : integer);
  78.     PROCEDURE SetDWindowStyle (theWind : WindowPtr;
  79.                                     font, size, wrap, just : integer);
  80.     FUNCTION GetDWindowTE (theWind : WindowPtr) : TEHandle;
  81.     FUNCTION IsDWindow (theWind : WindowPtr) : Boolean;
  82.     PROCEDURE TransDisplayInit;
  83.  
  84. IMPLEMENTATION
  85.  
  86. {    Display window types, constants, variables.}
  87.  
  88.     CONST
  89.         monaco = 4;
  90.  
  91.     TYPE
  92.         DIPtr = ^DisplayInfo;
  93.         DIHandle = ^DIPtr;
  94.         DisplayInfo = RECORD
  95.                 dWind : WindowPtr;        { display window         }
  96.                 dTE : TEHandle;            { window text            }
  97.                 dScroll : ControlHandle;    { window scroll bar      }
  98.                 dActivate : ProcPtr;        { notification procedure }
  99.                 dMaxText : longint;        { max text length        }
  100.                 dFlushAmt : longint;        { amount to autoflush    }
  101.                 dNext : DIHandle;            { next window structure  }
  102.             END;
  103.  
  104.  
  105.     VAR
  106.  
  107. { Look at TransDisplayInit procedure for initial values of these variables    }
  108.  
  109.         d_font, d_size : integer;                    { default font              }
  110.                                                 { default pointsize         }
  111.         d_wrap, d_just : integer;                { default word wrap (on)    }
  112.                                                 { default justification     }
  113.         d_maxText, d_flushAmt : longint;        { default max text allowed  }
  114.                                                 { default autoflush amount  }
  115.         d_activate : ProcPtr;                    { default notification proc }
  116.  
  117. {    Lowest allowable values for autoflush characteristics}
  118.  
  119.  
  120.         d_loMaxText, d_loFlushAmt : longint;
  121.  
  122.         dwList : DIHandle;
  123.  
  124. {    Variables pertaining to the display window being operated on}
  125. {    (updated, resized, etc.).  This window is not necessarily the}
  126. {    same as curDispWind!  These variables are synced to the window}
  127. {    with SyncGlobals. }
  128.  
  129.         dispInfo : DIHandle;        { info structure         }
  130.  
  131.         dispWind : WindowPtr;            { the window             }
  132.         dispTE : TEHandle;                { window text            }
  133.         dispScroll : ControlHandle;        { the scroll bar         }
  134.         dActivate : ProcPtr;                { notification procedure }
  135.         dMaxText, dFlushAmt : longint;        { max text allowed       }
  136.         { amount to flush        }
  137.  
  138. {    curDispWind is the current output window.}
  139. {    If curDispWind = nil, output is turned off.}
  140.  
  141.         curDispWind : WindowPtr;
  142.  
  143. { -------------------------------------------------------------------- }
  144. {                Miscellaneous Internal (private) Routines                }
  145. { -------------------------------------------------------------------- }
  146.  
  147.  
  148.  
  149. {    Draw grow box of dispWind in lower right hand corner}
  150.  
  151.     PROCEDURE DrawGrowBox;
  152.  
  153.         VAR
  154.             oldClip : RgnHandle;
  155.             r : Rect;
  156.  
  157.     BEGIN
  158.         r := dispWind^.portRect;
  159.         r.left := r.right - 15;        { draw only in corner }
  160.         r.top := r.bottom - 15;
  161.         oldClip := NewRgn;
  162.         GetClip(oldClip);
  163.         ClipRect(r);
  164.         DrawGrowIcon(dispWind);
  165.         SetClip(oldClip);
  166.         DisposeRgn(oldClip);
  167.     END;
  168.  
  169.  
  170.  
  171.  
  172. { -------------------------------------------------------------------- }
  173. {            Lowest-level Internal (Private) Display Window Routines        }
  174. { -------------------------------------------------------------------- }
  175.  
  176. {    Get display window info associated with window.}
  177. {    Return nil if window isn't a known display window.}
  178.  
  179.     FUNCTION GetDInfo (theWind : WindowPtr) : DIHandle;
  180.         VAR
  181.             h : DIHandle;
  182.             foundit : Boolean;
  183.     BEGIN
  184.         h := dwList;
  185.         foundit := false;
  186.         WHILE (h <> NIL) AND NOT foundit DO
  187.             BEGIN
  188.                 IF h^^.dWind = theWind THEN
  189.                     BEGIN
  190.                         GetDInfo := h;
  191.                         h := NIL;
  192.                         foundit := true;
  193.                     END
  194.                 ELSE
  195.                     h := h^^.dNext;
  196.             END;
  197.         IF NOT foundit THEN
  198.             GetDInfo := NIL;                    {make it a nop    }
  199.     END;
  200.  
  201. {    Synchronize globals to a display window.  theWind must be a legal}
  202. {    display window, with one exception:  if theWind is nil, the}
  203. {    variables are synced to the current port.  That is safe (and}
  204. {    correct) because:}
  205. {    (i)     nil is only passed by display window handler procedures,}
  206. {         which are only called by TransSkel for display window}
  207. {         events.}
  208. {    (ii) TransSkel always sets the port to the window before}
  209. {         calling the handler proc.}
  210. {    Hence, use of the current port under these circumstances}
  211. {    always produces a legal display window.}
  212.  
  213. {    SyncGlobals is not used in single display mode, because the}
  214. {    globals are all set by SetupDWindow and do not change thereafter.}
  215.  
  216.     PROCEDURE SyncGlobals (theWind : WindowPtr);
  217.  
  218.         VAR
  219.             dp : DIPtr;
  220.     BEGIN
  221.         IF theWind = NIL THEN                    { use current window }
  222.             GetPort(theWind);
  223.         dispWind := theWind;
  224.         dispInfo := GetDInfo(dispWind);
  225.         dp := dispInfo^;
  226.         dispScroll := dp^.dScroll;
  227.         dispTE := dp^.dTE;
  228.         dActivate := dp^.dActivate;
  229.         dMaxText := dp^.dMaxText;
  230.         dFlushAmt := dp^.dFlushAmt;
  231.     END;
  232.  
  233. {    Calculate the dimensions of the editing rectangle for}
  234. {    dispWind (which must be set properly and is assumed to }
  235. {    the current port).  (The viewRect and destRect are the}
  236. {    same size .) Assumes the port , text font and text size are all}
  237. {    set properly.  The viewRect is sized so that an integral}
  238. {    number of lines can be displayed in it, i.e., so that a}
  239. {    partial line never shows at the bottom. }
  240.  
  241.     PROCEDURE CalcEditRect (VAR r : Rect);
  242.  
  243.         VAR
  244.             f : FontInfo;
  245.             lineHeight : integer;
  246.  
  247.     BEGIN
  248.         GetFontInfo(f);
  249.         lineHeight := f.ascent + f.descent + f.leading;
  250.         r := dispWind^.portRect;
  251.         r.left := r.left + 4;
  252.         r.right := r.right - 17;            { leave room for scroll bar + 2 }
  253.         r.top := r.top + 2;
  254.         r.bottom := r.top + ((r.bottom - (r.top - 2)) DIV lineHeight) * lineHeight;
  255.     END;
  256.  
  257. {    Calculate the dimensions of the scroll bar rectangle for the}
  258. {    window.  Make sure that the edges overlap the window frame and}
  259. {    the grow box.}
  260.  
  261.     PROCEDURE CalcScrollRect (VAR r : Rect);
  262.  
  263.     BEGIN
  264.         r := dispWind^.portRect;
  265.         r.right := r.right + 1;
  266.         r.left := r.right - 16;
  267.         r.top := r.top - 1;
  268.         r.bottom := r.bottom - 14;
  269.     END;
  270.  
  271. {    Calculate the number of lines currently scrolled off}
  272. {    the top.}
  273.  
  274.     FUNCTION LinesOffTop : integer;
  275.  
  276.         VAR
  277.             ePtr : TEPtr;
  278.  
  279.     BEGIN
  280.         ePtr := dispTE^;
  281.         LinesOffTop := (ePtr^.viewRect.top - ePtr^.destRect.top) DIV ePtr^.lineHeight;
  282.     END;
  283.  
  284. {    Highlight the scroll bar properly.  This means that it's not}
  285. {    made active if the window itself isn't active, even if}
  286. {    there's enough text to fill the window. }
  287.  
  288.     PROCEDURE HiliteScroll;
  289.         VAR
  290.             result : integer;
  291.     BEGIN
  292.         IF (GetCtlMax(dispScroll) > 0) AND (dispWind = FrontWindow) THEN
  293.             result := 0
  294.         ELSE
  295.             result := 255;
  296.         HiliteControl(dispScroll, result);
  297.     END;
  298.  
  299. {    Scroll to the correct position.  lDelta is the}
  300. {    amount to CHANGE the current scroll setting by.}
  301. {    Positive scrolls the text up, negative down.}
  302.  
  303.     PROCEDURE ScrollText (lDelta : integer);
  304.  
  305.         VAR
  306.             lHeight, newLine, topLine : integer;
  307.  
  308.     BEGIN
  309.         lHeight := dispTE^^.lineHeight;
  310.         topLine := LinesOffTop;
  311.         newLine := topLine + lDelta;
  312.         IF newLine < 0 THEN
  313.             newLine := 0;
  314.         IF newLine > GetCtlmax(dispScroll) THEN
  315.             newLine := GetCtlMax(dispScroll);
  316.         SetCtlValue(dispScroll, newLine);
  317.         TEScroll(0, (topLine - newLine) * lHeight, dispTE);
  318.     END;
  319.  
  320.  
  321. {    Filter proc for tracking mousedown in scroll bar . The code}
  322. {    for the part originally hit is stored in the control 's reference}
  323. {    value by Mouse ( ) before calling this . }
  324.  
  325.  
  326. {    Scroll by one line if the mouse is in an arrow.  Scroll by a half}
  327. {    window's worth of lines if the mouse is in a page region. }
  328.  
  329.     PROCEDURE TrackScroll (theScroll : ControlHandle;
  330.                                     partCode : integer);
  331.  
  332.         VAR
  333.             lDelta, halfPage : integer;
  334.  
  335.     BEGIN
  336.         IF partCode = GetCRefCon(theScroll) THEN        { still in same part? }
  337.             BEGIN
  338.                 halfPage := ((dispTE^^.viewRect.bottom - dispTE^^.viewRect.top) DIV dispTE^^.lineHeight) DIV 2;
  339.                 IF halfPage = 0 THEN
  340.                     halfPage := halfPage + 1;
  341.                 CASE partCode OF
  342.                     inUpButton : 
  343.                         lDelta := -1;
  344.                     inDownButton : 
  345.                         lDelta := 1;
  346.                     inPageUp : 
  347.                         lDelta := -halfPage;
  348.                     inPageDown : 
  349.                         lDelta := halfPage;
  350.                     OTHERWISE
  351.                 END;
  352.                 ScrollText(lDelta);
  353.             END;
  354.     END;
  355.  
  356. {    Adjust the text in the text record and the scroll bar.  This is}
  357. {    called for major catastrophes, such as resizing the window, or}
  358. {    changing the word wrap style.  It makes sure the view and}
  359. {    destination rectangles are sized properly, and that the bottom}
  360. {    line of text never scrolls up past the bottom line of the}
  361. {    window, if there's enough to fill the window, and that the}
  362. {    scroll bar max and current values are set properly.}
  363.  
  364. {    Resizing the dest rect just means resetting the right edge}
  365. {    (the top is NOT reset), since text might be scrolled off the}
  366. {    top (i.e., destRect.top != 0).}
  367.  
  368.     PROCEDURE OverhaulDisplay;
  369.  
  370.         VAR
  371.             r : Rect;
  372.             nLines, visLines, topLines, scrollLines, lHeight : integer;
  373.             { number of lines in TERec }
  374.         { number of lines displayable in window }
  375.         { number of lines currently scrolled off top }
  376.         { number of lines to scroll down }
  377.  
  378.     BEGIN
  379.         CalcEditRect(r);
  380.         dispTE^^.destRect.right := r.right;
  381.         dispTE^^.viewRect := r;
  382.         TECalText(dispTE);        { recalc line starts }
  383.         lHeight := dispTE^^.lineHeight;
  384.         nLines := dispTE^^.nLines;
  385.         visLines := (r.bottom - r.top) DIV lheight;
  386.         topLines := LinesoffTop;
  387.  
  388. {    If the text doesn't fill the window (visLines > nLines - topLines),}
  389. {    pull the text down if possible (if topLines > 0).  Make sure}
  390. {    not to try to scroll down by more lines than are hidden off the top .}
  391.  
  392.         scrollLines := visLines - (nLines - topLines);
  393.         IF (scrollLines > 0) AND (topLines > 0) THEN
  394.             BEGIN
  395.                 IF scrollLines > topLines THEN
  396.                     scrollLines := topLines;
  397.                 TEScroll(0, scrollLInes * lHeight, dispTE);
  398.                 toplines := topLines - scrollLines;
  399.             END;
  400.         TEUpdate(r, dispTE);
  401.         IF nLines - visLines < 0 THEN
  402.             SetCtlMax(dispScroll, 0)
  403.         ELSE
  404.             SetCtlMax(dispScroll, nLines - VisLines);
  405.         SetCtlValue(dispScroll, topLines);
  406.         HiliteScroll;
  407.     END;
  408.  
  409.     PROCEDURE callpnoarg (myProc : ProcPtr);
  410.  
  411. { For all the Procedures that are called with no arguments                            }
  412.  
  413.     INLINE
  414.         $205f,     {movea.l  (a7)+,a0        ; (a0) is a ptr to string, 4(a0) is mode}
  415.         $4e90;
  416.  
  417.     PROCEDURE callpBoolean (myBool : Boolean;
  418.                                     myProc : ProcPtr);
  419.  
  420. { Two calls use Booleans as one parameter arguments.  This procedure handles    }
  421. { both of them.                                                                            }
  422.  
  423.     INLINE
  424.         $205f,     {movea.l  (a7)+,a0        ; (a0) is a ptr to string, 4(a0) is mode}
  425.         $4e90;
  426.  
  427. { ---------------------------------------------------------------- }
  428. {                        Window Handler Routines                        }
  429. { ---------------------------------------------------------------- }
  430.  
  431.  
  432.  
  433. {    When the window comes active, highlight the scroll bar appropriately.}
  434. {    When the window is deactivated, un-highlight the scroll bar.}
  435. {    Redraw the grow box.}
  436.  
  437. {    Notify the host as appropriate.}
  438.  
  439. {    Note that clicking close box hides the window, which generates a}
  440. {    deactivate event, so there is no need for a close notifier.}
  441.  
  442.  
  443.     PROCEDURE Activate (isActive : Boolean);
  444.  
  445.     BEGIN
  446.         SyncGlobals(NIL);                { sync to current port }
  447.         DrawGrowBox;
  448.         HiliteScroll;
  449.  
  450.         IF dActivate <> NIL THEN
  451.             callpBoolean(isActive, dActivate);
  452.     END;
  453.  
  454. {    Update window.  The update event might be in response to a}
  455. {    window resizing.  If so, move and resize the scroll bar,}
  456. {    and recalculate the text display.}
  457.  
  458. {    The ValidRect call is done because the HideControl adds the}
  459. {    control bounds box to the update region - which would generate}
  460. {    another update event!  Since everything is redrawn below anyway,}
  461. {    the ValidRect is used to cancel the update.}
  462.  
  463.     PROCEDURE Update (resized : Boolean);
  464.  
  465.         VAR
  466.             r : Rect;
  467.  
  468.     BEGIN
  469.         SyncGlobals(NIL);                    { sync to current port }
  470.         r := dispWind^.portRect;
  471.         EraseRect(r);
  472.         IF resized THEN
  473.             BEGIN
  474.                 HideControl(dispScroll);
  475.                 r := dispScroll^^.contrlRect;
  476.                 ValidRect(r);
  477.                 CalcScrollRect(r);
  478.                 SizeControl(dispScroll, 16, r.bottom - r.top);
  479.                 MoveControl(dispScroll, r.left, r.top);
  480.                 OverHaulDisplay;
  481.                 ShowControl(dispScroll);
  482.             END
  483.         ELSE
  484.             BEGIN
  485.                 r := dispTE^^.viewRect;
  486.                 TEUpdate(r, dispTE);
  487.             END;
  488.         DrawGrowBox;
  489.         DrawControls(dispWind);    { redraw scroll bar }
  490.     END;
  491.  
  492. {    Handle mouse clicks in window}
  493.  
  494.     PROCEDURE Mouse (thePt : Point;
  495.                                     t : longint;
  496.                                     mods : integer);
  497.  
  498.         VAR
  499.             thePart : integer;
  500.             oldCtlValue : integer;
  501.  
  502.     BEGIN
  503.         SyncGlobals(NIL);                    { Sync to current port    }
  504.         thePart := TestControl(dispScroll, thePt);
  505.         IF thePart = inThumb THEN
  506.             BEGIN
  507.                 OldCtlValue := GetCtlValue(dispScroll);
  508.                 IF TrackControl(dispScroll, thePt, NIL) = inThumb THEN
  509.                     ScrollText(GetCtlValue(dispScroll) - oldCtlValue);
  510.             END
  511.         ELSE IF thePart <> 0 THEN
  512.             BEGIN
  513.                 SetCRefCon(dispScroll, longint(thePart));
  514.                 oldCtlValue := TrackControl(dispScroll, thePt, @TrackScroll);
  515.             END;
  516.     END;
  517.  
  518. {    Remove the display window from the list, and dispose of it.}
  519. {    Since the clobber procedure is never called except for real display}
  520. {    windows, and since the list must therefore be non-empty, it is}
  521. {    not necessary to check the legality of the window or that the}
  522. {    window's in the list.}
  523.  
  524. {    Must do SetDWindow (nil) to turn output off, if the window being}
  525. {    clobbered is the current output window.}
  526.  
  527.     PROCEDURE Clobber;
  528.  
  529.         VAR
  530.             h, h2 : DIHandle;
  531.             keepgoing : Boolean;
  532.  
  533.     BEGIN
  534.         SyncGlobals(NIL);                    { sync to current port }
  535.         IF dispWind = curDispWind THEN    { is it the first window in list? }
  536.             SetDWindow(NIL);
  537.         IF dwList^^.dWind = dispWind THEN    { found it }
  538.             BEGIN
  539.                 h2 := dwList;
  540.                 dwList := dwList^^.dNext;
  541.             END
  542.         ELSE
  543.             BEGIN
  544.                 h := dwList;
  545.                 keepgoing := true;
  546.                 WHILE (h <> NIL) AND keepgoing DO
  547.                     BEGIN
  548.                         h2 := h^^.dNext;
  549.                         IF h2^^.dWind = dispWind THEN
  550.                             BEGIN
  551.                                 h^^.dNext := h2^^.dNext;
  552.                                 keepgoing := false;
  553.                             END;
  554.                         h := h2;
  555.                     END;
  556.             END;
  557.         DisposHandle(Handle(h2));        { get rid of information structure }
  558.         TEDispose(dispTE);                { toss text record }
  559.         DisposeWindow(dispWind);        { toss window and scroll bar }
  560.         dispWind := NIL;
  561.     END;
  562.  
  563. { ---------------------------------------------------------------- }
  564. {                            Control Routines                        }
  565. { ---------------------------------------------------------------- }
  566.  
  567.  
  568. {    Test whether a window is a legal display window or not }
  569.  
  570.     FUNCTION IsDWindow;
  571.  
  572.     BEGIN
  573.         IsDWindow := GetDInfo(theWind) <> NIL;
  574.     END;
  575.  
  576. {    Return handle to display window's text record}
  577.  
  578.     FUNCTION GetDWindowTE;
  579.  
  580.         VAR
  581.             dInfo : DIHandle;
  582.  
  583.     BEGIN
  584.         IF GetDInfo(theWind) = NIL THEN
  585.             GetDWindowTE := NIL
  586.         ELSE
  587.             GetDWIndowTE := dInfo^^.dTE;
  588.     END;
  589.  
  590. {    Change the text display characteristics of a display window}
  591. {    and redisplay it.  As a side effect, this always scrolls to the}
  592. {    home position.}
  593.  
  594.     PROCEDURE SetDWindowStyle;
  595.  
  596.         VAR
  597.             savePort : GrafPtr;
  598.             f : FontInfo;
  599.             te : TEHandle;
  600.             r : Rect;
  601.  
  602.     BEGIN
  603.         IF theWind = NIL THEN            { reset window creation defaults }
  604.             BEGIN
  605.                 d_font := font;
  606.                 d_size := size;
  607.                 d_wrap := wrap;
  608.                 d_just := just;
  609.             END
  610.         ELSE
  611.             BEGIN
  612.                 IF IsDWindow(theWind) THEN
  613.                     BEGIN
  614.                         GetPort(savePort);
  615.                         SyncGlobals(theWind);
  616.                         SetPort(dispWind);
  617.                         te := dispTE;
  618.                         r := te^^.viewRect;
  619.                         EraseRect(r);
  620.                         r := te^^.destRect;    { scroll home without redrawing }
  621.  
  622.                         OffsetRect(r, 0, 2 - r.top);
  623.                         te^^.destRect := r;
  624.                         te^^.crOnly := wrap;    { set word wrap }
  625.                         TESetJust(just, te);    { set justification }
  626.                         TextFont(font);         { set the font and point size }
  627.                         TextSize(size);        { of text record (this is the }
  628.                         GetFontInfo(f);        { hard part) }
  629.                         te^^.lineHeight := f.ascent + f.descent + f.leading;
  630.                         te^^.fontAscent := f.ascent;
  631.                         te^^.txFont := font;
  632.                         te^^.txSize := size;
  633.  
  634.                         OverhaulDisplay;
  635.                         SetPort(savePort);
  636.                     END;
  637.             END;
  638.     END;
  639.  
  640. {    Scroll the text in the window so that line lineNum is at the top.}
  641. {    First line is line zero.}
  642.  
  643.     PROCEDURE setDWindowPos;
  644.  
  645.         VAR
  646.             savePort : GrafPtr;
  647.  
  648.     BEGIN
  649.         IF IsDWindow(theWind) THEN
  650.             BEGIN
  651.                 GetPort(savePort);
  652.                 SyncGlobals(theWind);
  653.                 SetPort(dispWind);
  654.                 ScrollText(lineNum - GetCtlValue(dispScroll));
  655.                 SetPort(savePort);
  656.             END;
  657.     END;
  658.  
  659. {    Set display window activate notification procedure.}
  660. {    Pass nil to disable it.}
  661.  
  662.     PROCEDURE SetDWindowNotify;
  663.  
  664.         VAR
  665.             dInfo : DIHAndle;
  666.  
  667.     BEGIN
  668.         IF theWind = NIL THEN            { reset window creation default }
  669.             d_activate := p
  670.         ELSE
  671.             BEGIN
  672.                 dInfo := GetDInfo(theWind);
  673.                 IF dInfo <> NIL THEN
  674.                     dInfo^^.dActivate := p;
  675.             END;
  676.     END;
  677.  
  678. {    Set display window autoflush characteristics}
  679.  
  680.     PROCEDURE SetDWindowFlush;
  681.  
  682.         VAR
  683.             dInfo : DIHandle;
  684.  
  685.     BEGIN
  686.         IF maxText > longint(32767) THEN
  687.             maxText := 32767;
  688.         IF maxText < d_loMaxText THEN
  689.             maxText := d_loMaxText;
  690.         IF flushAmt < d_loFlushAmt THEN
  691.             flushAmt := d_loFlushAmt;
  692.         IF theWind = NIL THEN
  693.             BEGIN            { reset window creation defaults }
  694.                 d_maxText := maxText;
  695.                 d_flushAmt := flushAmt;
  696.             END
  697.         ELSE
  698.             BEGIN
  699.                 dInfo := GetDInfo(theWind);
  700.                 IF dInfo <> NIL THEN
  701.                     BEGIN
  702.                         dInfo^^.dMaxText := maxText;
  703.                         dInfo^^.dFlushAmt := flushAmt;
  704.                     END;
  705.             END;
  706.     END;
  707.  
  708. {    Set which display window is to be used for output.  If theWind}
  709. {    is nil, output is turned off.  If theWind is not a legal display}
  710. {    window, nothing is done.}
  711.  
  712.     PROCEDURE SetDWindow;
  713.  
  714.     BEGIN
  715.         IF (theWind = NIL) OR IsDWindow(theWind) THEN
  716.             curDispWind := theWind;
  717.     END;
  718.  
  719. {    Get the WindowPtr of the current output display window.  If}
  720. {    output is turned off, this will be nil.}
  721.  
  722.     PROCEDURE GetDWindow;
  723.  
  724.     BEGIN
  725.         theWind := curDispWind;
  726.     END;
  727.  
  728. {    Flush text from the window and readjust the display.}
  729.  
  730.     PROCEDURE FlushDWindow;
  731.  
  732.     BEGIN
  733.         IF IsDWindow(theWind) THEN
  734.             BEGIN
  735.                 SyncGlobals(theWind);
  736.                 TESetSelect(longint(0), byteCount, dispTE);    { select text }
  737.                 TEDelete(dispTE);                                { clobber it }
  738.                 OverhaulDisplay;
  739.             END;
  740.     END;
  741.  
  742. {    Create and initialize a display window and the associated data}
  743. {    structures, and return the window pointer.  Install window in}
  744. {    list of display windows.}
  745.  
  746.     PROCEDURE SetupDWindow;
  747.  
  748.         VAR
  749.             r : Rect;
  750.             savePort : GrafPtr;
  751.             dInfo : DIHandle;
  752.  
  753.     BEGIN
  754.         GetPort(savePort);
  755.         SkelWindow(dispWind, @Mouse, NIL, @Update, @Activate, NIL, @Clobber, NIL, false);
  756.     { the window }
  757.         { mouse click handler }
  758.         { key clicks are ignored }
  759.         { window updating procedure }
  760.         { window activate/deactivate procedure }
  761.         { TransSkel hides window if no close proc }
  762.         { (generates deactivate event) }
  763.         { window disposal procedure }
  764.         { no idle proc }
  765.         { irrelevant since no idle proc }
  766.  
  767. {    Build the scroll bar.  Make sure the borders overlap the}
  768. {    window frame and the frame of the grow box.}
  769.  
  770.         CalcScrollRect(r);
  771.         dispScroll := NewControl(dispWind, r, '', true, 0, 0, 0, scrollBarProc, longint(0));
  772.  
  773. {    Create the TE record used for text display.  Use defaults for}
  774. {    display characteristics.  Setting window style overhauls}
  775. {    display, so can cancel and update event pending for the window.}
  776.  
  777.         CalcEditRect(r);
  778.         dispTE := TENew(r, r);
  779.  
  780. {    Get new information structure, attach to list of known display}
  781. {    windows.}
  782.  
  783.         dInfo := DIHandle(NewHandle(sizeof(DisplayInfo)));
  784.  
  785.         dInfo^^.dNext := dwList;
  786.         dwList := dInfo;
  787.         dInfo^^.dWind := dispWind;
  788.         dInfo^^.dScroll := dispScroll;
  789.         dInfo^^.dTE := dispTE;
  790.  
  791.         SetDWindowNotify(dispWind, d_activate);
  792.         SetDWindowFlush(dispWind, d_maxtext, d_flushAmt);
  793.         SetDWindowStyle(dispWind, d_font, d_size, d_wrap, d_just);
  794.  
  795. {    Make window current display output window}
  796.  
  797.         SetDWindow(dispWind);
  798.         SetPort(savePort);
  799.     END;
  800.  
  801. {    Create and initialize a display window and the associated data}
  802. {    structures, and return the window pointer.  Install window in}
  803. {    list of display windows.  In single-window mode, disallow}
  804. {    creation of a new window if one already exists.}
  805.  
  806. {    The parameters are similar to those for NewWindow.  See Inside}
  807. {    Macintosh.}
  808.  
  809.     FUNCTION NewDWindow;
  810.  
  811.     BEGIN
  812.         dispWind := NewWindow(NIL, bounds, title, visible, documentProc, behind, goAway, refCon);
  813.         SetUpDWindow;
  814.         NewDWindow := dispWind;
  815.     END;
  816.  
  817. {    Create and initialize a display window (using a resource) and}
  818. {    the associated data structures, and return the window pointer.}
  819. {    Install window in list of display windows.  In single-window}
  820. {    mode, disallow creation of a new window if one already exists.}
  821.  
  822. {    The parameters are similar to those for GetNewWindow.  See Inside}
  823. {    Macintosh.}
  824.  
  825.     FUNCTION GetNewDWindow;
  826.  
  827.     BEGIN
  828.         dispWind := GetNewWindow(resourceNum, NIL, behind);
  829.         SetUPDWindow;
  830.         GetNewDWindow := dispWind;
  831.     END;
  832.  
  833. { ------------------------------------------------------------ }
  834. {                        Output Routines                            }
  835. { ------------------------------------------------------------ }
  836.  
  837.  
  838. {}
  839. {    Write text to display area if output is on (curDispWind != nil).}
  840. {    DisplayText is the fundamental output routine.  All other}
  841. {    output calls map (eventually) to it.}
  842.  
  843. {    First check whether the insertion will cause overflow and flush}
  844. {    out some stuff if so.  Insert new text at the end, then test}
  845. {    whether lines must be scrolled to get the new stuff to show up.}
  846. {    If yes, then do the scroll.  Set values of scroll bar properly}
  847. {    and highlight as appropriate.}
  848.  
  849. {    The current port is preserved.  Since all output calls end up}
  850. {    here, it's the only output routine that has to save the port}
  851. {    and check whether output is on.}
  852.  
  853.     PROCEDURE DisplayText;
  854.  
  855.         VAR
  856.             nLines, dispLines, topLines, scrollLines, lHeight : integer;
  857.         { number of lines in TERec }
  858.         { number of lines displayable in window }
  859.         { number of lines currently scrolled off top }
  860.         { number of lines to scroll up }
  861.             r : Rect;
  862.             savePort : GrafPtr;
  863.             dTE : TEHandle;
  864.  
  865.     BEGIN
  866.         IF curDispWind <> NIL THEN
  867.             BEGIN
  868.                 GetPort(savePort);
  869.                 SetPort(curDispWind);
  870.                 SyncGlobals(curDispWind);
  871.                 dTE := dispTE;
  872.  
  873.                 IF dTE^^.teLength + len > dMaxText THEN    { check overflow }
  874.                     BEGIN
  875.                         FlushDWindow(dispWind, dFlushAmt);
  876.                         DisplayString('(autoflush occurred)');
  877.                     END;
  878.                 lHeight := dTE^^.lineHeight;
  879.                 TESetSelect(longint(32767), longint(32767), dTE);
  880.                 TEInsert(theText, len, dTE);
  881.                 r := dTE^^.viewRect;
  882.                 nLines := dTE^^.nLines;
  883.                 dispLines := (r.bottom - r.top) DIV lHeight;
  884.                 topLines := LinesOffTop;
  885.                 scrollLines := nLines - (topLines + dispLines);
  886.                 IF scrollLines > 0 THEN                                 { must scroll up }
  887.                     TEScroll(0, -lHeight * scrollLines, dTE);            { scroll up }
  888.                 topLines := nLines - dispLines;
  889.                 IF (topLines >= 0) AND (GetCtlMax(dispScroll) <> topLines) THEN
  890.                     BEGIN
  891.                         SetCtlMax(dispScroll, topLines);
  892.                         SetCtlValue(dispScroll, topLines);
  893.                     END;
  894.                 HiliteScroll;
  895.                 SetPort(savePort);
  896.             END;
  897.     END;
  898.  
  899. {    Derived output routines:}
  900.  
  901. {    DisplayString    Write (Pascal) string}
  902.  
  903. {    DisplayLong        Write value of long integer}
  904. {    DisplayInt        Write value of integer}
  905. {    DisplayChar        Write character}
  906.  
  907. {    DisplayHexLong    Write value of long integer in hex (8 digits)}
  908. {    DisplayHexInt    Write value of integer in hex (4 digits)}
  909. {    DisplayHexChar    Write value of character in hex (2 digit)}
  910.  
  911. {    DisplayBoolean    Write boolean value}
  912. {    DisplayLn        Write carriage return}
  913.  
  914.     PROCEDURE DisplayString;
  915.  
  916.         VAR
  917.             myPtr : Ptr;
  918.  
  919.     BEGIN
  920.         myPtr := Ptr(longint(@theStr) + 1);
  921.         DisplayText(myPtr, longint(theStr[0]));
  922.     END;
  923.  
  924.     PROCEDURE DisplayLong;
  925.  
  926.         VAR
  927.             s : Str255;
  928.  
  929.     BEGIN
  930.         NumToString(l, s);
  931.         DisplayString(s);
  932.     END;
  933.  
  934.     PROCEDURE DisplayInt;
  935.  
  936.     BEGIN
  937.         DisplayLong(longint(i));
  938.     END;
  939.  
  940.     PROCEDURE DisplayChar;
  941.  
  942.         VAR
  943.             myPtr : Ptr;
  944.  
  945.     BEGIN
  946.         myPtr := @c;
  947.         myPtr := Ptr(longint(myPtr) + 1);
  948.         DisplayText(myPtr, longint(1));
  949.     END;
  950.  
  951.     PROCEDURE DisplayLn;
  952.  
  953.     BEGIN
  954.         DisplayChar(char(13));
  955.     END;
  956.  
  957.     PROCEDURE DisplayBoolean;
  958.  
  959.     BEGIN
  960.         IF b THEN
  961.             DisplayString('True')
  962.         ELSE
  963.             DisplayString('False');
  964.     END;
  965.  
  966.     PROCEDURE HexByte (value : integer);    {value should be 0..15}
  967.     BEGIN
  968.         IF value < 10 THEN
  969.             DisplayChar(char(value + integer('0')))
  970.         ELSE
  971.             DisplayChar(char(value + (integer('a') - 10)));
  972.     END;
  973.  
  974.     PROCEDURE DisplayHexChar;
  975.  
  976.     BEGIN
  977.         HexByte(integer(BitAnd(BitShift(longint(c), -4), $0000000f)));
  978.         HexByte(integer(BitAnd(longint(c), $0000000f)));
  979.     END;
  980.  
  981.     PROCEDURE DisplayHexInt;
  982.  
  983.     BEGIN
  984.         DisplayHexChar(char(BitAnd(BitShift(longint(i), -8), $000000ff)));
  985.         DisplayHexChar(char(BitAnd(longint(i), $000000ff)));
  986.     END;
  987.  
  988.     PROCEDURE DisplayHexLong;
  989.  
  990.     BEGIN
  991.         DisplayHexInt(Integer(BitAnd(BitShift(l, -16), $0000ffff)));
  992.         DisplayHexInt(integer(BitAnd(l, $0000ffff)));
  993.     END;
  994.  
  995.     PROCEDURE TransDisplayInit;
  996.  
  997.     BEGIN
  998.  
  999. {    Default values for display window characteristics}
  1000.  
  1001.         d_font := monaco;        { default font              }
  1002.         d_size := 9;                { default pointsize         }
  1003.         d_wrap := 0;                { default word wrap (on)    }
  1004.         d_just := teJustLeft;    { default justification     }
  1005.         d_maxText := 30000;    { default max text allowed  }
  1006.         d_flushAmt := 25000;    { default autoflush amount  }
  1007.         d_activate := NIL;        { default notification proc }
  1008.  
  1009. {    Lowest allowable values for autoflush characteristics}
  1010.  
  1011.         d_loMaxText := 100;
  1012.         d_loFlushAmt := 100;
  1013.  
  1014. {    dwList points to a list of structures describing the known display}
  1015. {    windows.}
  1016.  
  1017. {    curDispWind is the current output window.}
  1018. {    If curDispWind = nil, output is currently turned off.}
  1019.  
  1020.         dwList := NIL;
  1021.         dispWind := NIL;
  1022.         curDispWind := NIL;
  1023.     END;
  1024. END.